package graph.transform;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import graph.Edge;
import graph.Graph;
import graph.Node;

public class GMLTransformer {
	private Graph graph;
	private int nextId = 0;

	public GMLTransformer(Graph graph) {
		this.graph = graph;
	}
	public Set<Node> newNode(int n) {
		HashSet<Node> result = new HashSet<Node>();
		for (int i=0 ; i<n ; i++) {
			result.add(new Node(++nextId));
		}
		graph.nodes.addAll(result);
		return result;
	}
	public Set<Node> newNode() { return newNode(1); }
	public Set<Node> addChild(Collection<Node> nodes) {
		return addChild(nodes, 1);
	}
	public Set<Node> addChild(Collection<Node> nodes, int n) {
		HashSet<Node> result = new HashSet<Node>();
		for (Node node : nodes) {
			for (int i=0 ; i<n ; i++) {
				Node child = new Node(++nextId); 
				result.add(child);
				graph.edges.add(new Edge(node, child));
			}
		}
		graph.nodes.addAll(result);
		return result;
	}
	public Set<Edge> ring(Set<Node> nodes) {
		HashSet<Edge> result = new HashSet<Edge>();
		Node[] tab = nodes.toArray(new Node[0]);
		for (int i=0 ; i<tab.length ; i++) {
			Edge edge = new Edge(tab[i], tab[(i+1)%tab.length]);
			result.add(edge);
		}
		graph.edges.addAll(result);
		return result;
	}
	public Set<Edge> edges(Set<Node> nodes) {
		HashSet<Edge> result = new HashSet<Edge>();
		for (Edge edge : graph.edges) {
			if (nodes.contains(edge.a) && nodes.contains(edge.b)) {
				result.add(edge);
			}
		}
		return result;
	}
	public Set<Node> addMiddle(Set<Edge> edges) {
		HashSet<Node> result = new HashSet<Node>();
		for (Edge edge : edges) {
			Node c = new Node(++nextId);
			result.add(c);
			graph.edges.add(new Edge(edge.a, c));
			graph.edges.add(new Edge(edge.b, c));
		}
		graph.nodes.addAll(result);
		return result;
	}
	public Set<Node> replaceMiddle(Set<Edge> edges) {
		Set<Node> result = addMiddle(edges);
		graph.edges.removeAll(edges);
		return result;
	}
	public Set<Node> edgeCount(int n) {
		return edgeCount(graph.nodes, n);
	}
	public Set<Node> edgeCount(Collection<Node> nodes, int n) {
		HashSet<Node> result = new HashSet<Node>();
		HashMap<Node, Integer> hist = new HashMap<Node, Integer>();
		for (Edge edge : graph.edges) {
			if (nodes.contains(edge.a)) {
				Integer c = hist.get(edge.a);
				if (c == null) {
					c = 0;
				}
				hist.put(edge.a, c+1);
			}
			if (nodes.contains(edge.b)) {
				Integer c = hist.get(edge.b);
				if (c == null) {
					c = 0;
				}
				hist.put(edge.b, c+1);
			}
		}
		for (Node node : nodes) {
			for (int i=0 ; i<n ; i++) {
				Node child = new Node(++nextId); 
				result.add(child);
				graph.edges.add(new Edge(node, child));
			}
		}
		graph.nodes.addAll(result);
		return result;
	}
	public Set<Edge> connect(Collection<Node> a, Collection<Node> b) {
		HashSet<Edge> result = new HashSet<Edge>();
		for (Node na : a) {
			for (Node nb : b) {
				result.add(new Edge(na,nb));
			}
		}
		graph.edges.addAll(result);
		return result;
	}
	public Set<Edge> connectIfDistance(Collection<Node> a, int distance) {
		HashSet<Edge> result = new HashSet<Edge>();
		for (Node n : a) {
			Set<Node> candidates = graph.getNodesOfDistance(n, distance);
			for (Node b : candidates) {
				if (a.contains(b)) {
					result.add(new Edge(n, b));
				}
			}
		}
		graph.edges.addAll(result);
		return result;
	}
	public void delete() {
		graph.nodes.clear();
		graph.edges.clear();
	}
	public void deleteNodes(Collection<Node> nodes) {
		for (Iterator<Edge> i = graph.edges.iterator() ; i.hasNext() ;) {
			Edge e = i.next();
			if (nodes.contains(e.a) || nodes.contains(e.b)) {
				i.remove();
			}
		}
		graph.nodes.removeAll(nodes);
	}
	public void deleteEdges(Collection<Edge> edges) {
		graph.edges.removeAll(edges);
	}
	public Set<Node> addChild(int n) {
		return addChild(graph.nodes, n);
	}
	List<Set<Node>> getRings(int n) {
		for (Node node : graph.nodes) {
			process(node, n);
		}
		
		
		return null;
	}
	private void process(Node node, int n) {
		HashMap<Node, Set<Node>> childs = new HashMap<Node, Set<Node>>();
		childs.put(node, graph.neighbours(node));
		for (int i=0 ; i<n ; i++) {
			childs.put(node, graph.neighbours(node));
			
		}
	}
}
